#include <stdio.h>
#include <stdlib.h>
#include "MemBlocks.h"
#include "MemChunks.h"

CMemBlocks::CMemBlocks(BlockType bt, unsigned int nIndx, unsigned int nSize, CMemChunks *mc)
    : m_bt(bt), m_nIndx(nIndx), m_nBlockSize(nSize), m_pChunks(mc)
{
}

CMemBlocks::~CMemBlocks()
{
    Destroy();
}

void CMemBlocks::FreeListNode(BlockNode *pNode)
{
    if (nullptr != pNode)
        free(pNode);
}

bool CMemBlocks::Initialize()
{
    m_lstUsing.SetData(this);
    // m_pUsingList->SetListNodeFree(&CMemBlocks::FreeListNode, this);

    if (SMALL_BLOCK == m_bt)
    {
        m_lstFree.SetData(this);
        // m_pFreeList->SetListNodeFree(&CMemBlocks::FreeListNode, this);
    }

    return true;
}

bool CMemBlocks::Destroy()
{
    if (!m_lstUsing.IsEmpty())
        m_lstUsing.Destroy();

    if (!m_lstFree.IsEmpty())
        m_lstFree.Destroy();

    return true;
}

void *CMemBlocks::Alloc(unsigned int nSize)
{
    BlockNode *pBlock = nullptr;
    unsigned int nHeaderSize = sizeof(BlockNode);

    if (SMALL_BLOCK == m_bt)
    {
        if (0 < m_lstFree.GetSize())
            pBlock = m_lstFree.PopBack();

        if (nullptr == pBlock)
            pBlock = (BlockNode *)m_pChunks->Alloc(m_nBlockSize + nHeaderSize, SMALL_BLOCK);
    }
    else
    {
        pBlock = (BlockNode *)m_pChunks->Alloc(nSize + nHeaderSize, LARGE_BLOCK);
    }

    if (nullptr == pBlock)
    {
        printf("Error (nullptr == pBlock):\tfile=%s\tline=%d\n", __FILE__, __LINE__);
        return nullptr;
    }

    m_lstUsing.PushBack(pBlock);

    return (void *)((char *)pBlock + nHeaderSize);
}

bool CMemBlocks::Free(void *pBlock)
{
    bool bRet = false;
    BlockNode *pIntBlock = (BlockNode *)pBlock;

    if (nullptr == pIntBlock)
    {
        printf("Error (nullptr == pIntBlock):\tfile=%s\tline=%d\n", __FILE__, __LINE__);
        return false;
    }

    bRet = m_lstUsing.Remove(pIntBlock);

    if (bRet)
    {
        if (SMALL_BLOCK == m_bt)
        {
            bRet = m_lstFree.PushFront(pIntBlock);
        }
        else
        {
            m_pChunks->Free(pIntBlock, LARGE_BLOCK);
        }
    }

    return bRet;
}
